package zli.proxy.dynamicproxy.gpproxy.proxy;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @Desc
 * @Author Zerlinda
 * @Date 2022/5/16 11:43
 * @Version 1.0
 */
public class GPProxy {

    public static final String ln = "\n";

    public static Object newProxyInstance(GPClassLoader loader,
                                          Class<?>[] interfaces,
                                          GPInvocationHandler h) {
        try {
            // 1. 动态生成源码.java文件
            String src = generateSrc(interfaces);

            // 2. Java文件输出到磁盘，保存为文件$Proxy0.java
            String filePath = GPProxy.class.getResource("").getPath();
            File f = new File(filePath + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();

            // 3. 把.java文件编译成$Proxy0.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(f);

            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
            task.call();
            manager.close();

            // 4. 把生成的.class文件加载到JVM中
            Class proxyClass = loader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);

            // 5. 返回新的代理对象
            return c.newInstance(h);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String generateSrc(Class<?>[] interfaces) {
        StringBuilder sb = new StringBuilder();
        sb.append("package zli.proxy.dynamicproxy.gpproxy.proxy;" + ln);
        sb.append("import zli.proxy.dynamicproxy.gpproxy.client.IPerson;" + ln);
        sb.append("import java.lang.reflect.*;" + ln);
        sb.append("public final class $Proxy0 implements " + interfaces[0].getName() + " {" + ln);
        sb.append("GPInvocationHandler h;" + ln);
        sb.append("public $Proxy0(GPInvocationHandler h) { " + ln);
        sb.append("     this.h = h;" + ln);
        sb.append("}" +ln);

        for(Method m : interfaces[0].getMethods()) {
            Class<?> [] params = m.getParameterTypes();

           /* StringBuilder paramsNames = new StringBuilder();
            StringBuilder paramsValues = new StringBuilder();
            StringBuilder paramsClasses = new StringBuilder();

            for (int i = 0; i <params.length; i++) {
                Class clazz = params[i];
                String type = clazz.getName();
            }*/

            sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "()" + "{" + ln);
            sb.append(" try { " + ln);
                //  super.h.invoke(this, m3, (Object[])null);
                //  m3 = Class.forName("zli.proxy.dynamicproxy.jdkproxy.IPerson").getMethod("findLove");
            sb.append("     Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\", new Class[] {});" + ln);
            sb.append("     this.h.invoke(this, m, (Object[])null);" + ln);
            sb.append("     return;" + ln);
            sb.append(" } catch (RuntimeException | Error var2) {"  + ln );
            sb.append("            throw var2;" + ln );
            sb.append(" } catch (Throwable var3) {" + ln );
            sb.append("            throw new UndeclaredThrowableException(var3);" + ln );
            sb.append(" }" + ln );
            sb.append("}" + ln );
        }
        sb.append("}");

        return sb.toString();

    }
}
